<?php

namespace app\command;

use think\Cache;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\Db;
use think\Exception;

class CronRun extends Command
{
    protected function configure()
    {
        $this->setName('corn:run')->setDescription('定时任务调度');
    }

    protected function execute(Input $input, Output $output)
    {
        // 获取待执行任务（包括需要重试的）
        $tasks = Db::name('cron_tasks')
            ->where('status', '<>', 2) // 非成功状态
            ->where(function ($query) {
                $query->where('status', 0) // 待执行
                ->whereOr('next_retry', '<=', date('Y-m-d H:i:s')); // 或达到重试时间
            })
            ->select();

        foreach ($tasks as $task) {
            // 在任务开始时增加锁机制
            $lockKey = 'cron_lock_' . $task['id'];
            if (Cache::has($lockKey)) {
                continue;
            }
            Cache::set($lockKey, true, 60);

            // 更新任务状态为执行中
            Db::name('cron_tasks')->where('id', $task['id'])->update([
                'status' => 1,
                'last_exec' => date('Y-m-d H:i:s')
            ]);

            try {
                // 设置超时处理
//                $this->setTimeout($task['timeout']);

                // 执行任务
                $this->runTask($task['task_name'], json_decode($task['params'], true));

                // 标记成功
                Db::name('cron_tasks')->where('id', $task['id'])->update([
                    'status' => 2,
                    'retry_count' => $task['retry_count'] + 1
                ]);
            } catch (\Exception $e) {
                // 处理失败
                $this->handleFailure($task,$e->getMessage());
            } finally {
                // 清除超时设置
//                pcntl_alarm(0);
            }
        }
    }

    protected function runTask($taskName, $params)
    {
        // 根据任务名执行不同逻辑（示例）
        $class = "\\app\\task\\" . ucfirst($taskName);
        if (class_exists($class)) {
            $task = new $class;
            $task->execute($params);
            return;
        }
        throw new \Exception("Task {$taskName} not found");
    }

    protected function setTimeout($seconds)
    {
        if ($seconds <= 0) return;

        // 设置超时信号处理
        pcntl_signal(SIGALRM, function () {
            throw new \Exception("Task execution timeout");
        });
        pcntl_alarm($seconds);
    }

    protected function handleFailure($task, $error)
    {
        $retryCount = $task['retry_count'] + 1;
        $maxRetry = $task['max_retry'] ?? 3;

        // 检查是否达到最大最大重试次数
        if ($retryCount >= $maxRetry) {
            $status = 3; // 永久失败
            $nextRetry = null;
        } else {
            $status = 0;
            $nextRetry = date('Y-m-d H:i:s', time() + $this->getRetryDelay($retryCount));
        }

        // 更新任务状态
        Db::name('cron_tasks')->where('id', $task['id'])->update([
            'status' => $status,
            'retry_count' => $retryCount,
            'next_retry' => $nextRetry,
            'error_log' => "Attempt {$retryCount}: " . $error
        ]);

        // 记录错误日志
        trace("Task failed: {$task['task_name']} - {$error}", 'error');
    }

    protected function getRetryDelay($attempt)
    {
        // 指数退避策略：5s, 15s, 30s, 60s...
        return min(300, pow(2, $attempt) * 5);
    }
}